www.gusucode.com > VC 使用图形方式显示动态数字 -源码程序 > VC 使用图形方式显示动态数字 -源码程序/code/ClockCtrl.cpp
//Download by http://www.NewXing.com /* Module : CLOCKCTRL.CPP Purpose: Implementation for an MFC GUI control which implements an analog clock Created: PJN / 01-02-2000 History: PJN / 16-02-2000 1. Removed noticable flicker which sometimes occurred when the seconds hand moved Copyright (c) 2000 by PJ Naughter. All rights reserved. */ ///////////////////////////////// Includes ////////////////////////////////// #include "stdafx.h" #include <math.h> #include "ClockCtrl.h" ///////////////////////////////// Macros ////////////////////////////////////// const double PI = 3.14159; #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////// Implementation ////////////////////////////// BEGIN_MESSAGE_MAP(CClockCtrl, CStatic) //{{AFX_MSG_MAP(CClockCtrl) ON_WM_PAINT() ON_WM_SIZE() ON_WM_TIMER() ON_WM_DESTROY() ON_WM_ERASEBKGND() //}}AFX_MSG_MAP END_MESSAGE_MAP() CClockCtrl::CClockCtrl() { //Initialize the member variables to their default values m_ColorHourMinutesHand = GetSysColor(COLOR_HIGHLIGHT); m_ColorPoints = GetSysColor(COLOR_BTNFACE); m_nXRadius = -1; m_nYRadius = -1; m_nPointWidth = -1; m_nHour = 0; m_nMinute = 0; m_nSecond = 0; m_nTimerID = 0; m_bEnableRealtime = TRUE; m_bShowHours = TRUE; m_bShowMinutes = TRUE; m_bShowSeconds = TRUE; m_bShowPoints = TRUE; m_bShowMinorPoints = TRUE; m_ColorBackground = GetSysColor(COLOR_BTNFACE); m_b3dPoints = TRUE; } void CClockCtrl::PreSubclassWindow() { //Let the parent class do its thing CStatic::PreSubclassWindow(); //Setup the timer if we are displaying realtime values if (m_bEnableRealtime) SetRealTime(TRUE); } void CClockCtrl::OnPaint() { //Force a recalc if not initialized if (m_nXRadius == -1) RecalcLayout(); // device context for painting CPaintDC dc(this); //Setup the brush we are going to use CBrush PointBrush(m_ColorPoints); CBrush* pOldBrush = dc.SelectObject(&PointBrush); //Draw the points going around the clock if (m_bShowPoints) { for (int nMinute=0; nMinute<60; nMinute++) { //Work out the face length which is different //depending on where we are on the ellipse edge CPoint p = ComputePoint(nMinute, 0.9); if ((nMinute % 5) == 0) DrawFacePoint(dc, p, TRUE); else if (m_bShowMinorPoints) DrawFacePoint(dc, p, FALSE); } } //Restore the DC dc.SelectObject(pOldBrush); //Then draw all the hands DrawHands(dc, m_nHour, m_nMinute, m_nSecond, TRUE); } void CClockCtrl::DrawHands(CDC& dc, int nHour, int nMinute, int nSecond, BOOL bDrawAll) { //Validate our parameters ASSERT(nHour >= 0 && nHour <= 12); ASSERT(nMinute >= 0 && nMinute <= 59); ASSERT(nSecond >= 0 && nSecond <= 59); //Setup the brush we are going to use CBrush PointBrush(m_ColorHourMinutesHand); CBrush* pOldBrush = dc.SelectObject(&PointBrush); if (bDrawAll) { //Draw the hour hand if (m_bShowHours) DrawHand(dc, nHour, HOUR, TRUE); //Draw the minute hand if (m_bShowMinutes) DrawHand(dc, nMinute, MINUTE, TRUE); //Draw the seconds hand if (m_bShowSeconds) DrawHand(dc, nSecond, SECOND, TRUE); } else { //Hour or minute is changing, erase both if (((m_nHour != nHour) || (m_nMinute != nMinute))) { //Erase the seconds hand if (m_bShowSeconds) DrawHand(dc, m_nSecond, SECOND, FALSE); //Erase the minute hand if (m_bShowMinutes) DrawHand(dc, m_nMinute, MINUTE, FALSE); //Erase the hour hand if (m_bShowHours) DrawHand(dc, m_nHour, HOUR, FALSE); //Draw the hour hand if (m_bShowHours) DrawHand(dc, nHour, HOUR, TRUE); //Draw the minute hand if (m_bShowMinutes) DrawHand(dc, nMinute, MINUTE, TRUE); //Draw the seconds hand if (m_bShowSeconds) DrawHand(dc, nSecond, SECOND, TRUE); } else { //Erase the seconds hand if (m_bShowSeconds) DrawHand(dc, m_nSecond, SECOND, FALSE); //Draw the seconds hand if (m_bShowSeconds) DrawHand(dc, nSecond, SECOND, TRUE); } } //Store away the new values m_nHour = nHour; m_nMinute = nMinute; m_nSecond = nSecond; //Restore the DC dc.SelectObject(pOldBrush); } void CClockCtrl::SetTime(int nHour, int nMinute, int nSecond) { //Validate our parameters ASSERT(m_hWnd); ASSERT(nHour >= 0 && nHour <= 12); ASSERT(nMinute >= 0 && nMinute <= 59); ASSERT(nSecond >= 0 && nSecond <= 59); //Do the updated drawing of the hands CClientDC dc(this); DrawHands(dc, nHour, nMinute, nSecond, FALSE); } double CClockCtrl::MinuteToRadian(double minute) { return (minute-15)*PI/30; } CPoint CClockCtrl::ComputePoint(int nMinute, double ratio) { CPoint point; double angle = MinuteToRadian(nMinute); point.x = m_MiddlePoint.x + (int) (m_nXRadius*ratio*cos(angle) + 0.5); point.y = m_MiddlePoint.y + (int) (m_nYRadius*ratio*sin(angle) + 0.5); return point; } void CClockCtrl::DrawFacePoint(CDC& dc, const CPoint& point, BOOL bMajor) { //Work out the size of the point rectangle CRect rPoint(point, point); if (bMajor) { int nPointRadius = m_nPointWidth / 2 + 1; rPoint.InflateRect(nPointRadius, nPointRadius); //Do the actual point drawing dc.Rectangle(&rPoint); if (m_b3dPoints) dc.Draw3dRect(&rPoint, GetSysColor(COLOR_BTNHIGHLIGHT), GetSysColor(COLOR_BTNSHADOW)); } else { if (m_bShowMinorPoints) { rPoint.InflateRect(1, 1); //Do the actual point drawing dc.Draw3dRect(&rPoint, GetSysColor(COLOR_BTNHIGHLIGHT), GetSysColor(COLOR_BTNSHADOW)); } } } void CClockCtrl::DrawHand(CDC& dc, int nMinute, HandType type, BOOL bDraw) { //Calculate the point positions of the hand CPoint handPoints[4]; GetHandPoints(nMinute, type, handPoints); if (type == SECOND) { //Draw the hand //dc.Polygon(handPoints, 2); int nOldRop = dc.SetROP2(R2_NOTXORPEN); dc.MoveTo(handPoints[0]); dc.LineTo(handPoints[1]); dc.SetROP2(nOldRop); } else { //Pick the correct colors to be used COLORREF colorBrush; COLORREF colorPen; if (bDraw) { colorBrush = m_ColorHourMinutesHand; colorPen = RGB(0, 0, 0); } else { colorBrush = m_ColorBackground; colorPen = m_ColorBackground; } //Setup the DC CBrush brushHand(colorBrush); CPen penHand(PS_SOLID, 1, colorPen); CBrush* pOldBrush = dc.SelectObject(&brushHand); CPen* pOldPen = dc.SelectObject(&penHand); //Draw the hand dc.Polygon(handPoints, 4); //Restore the DC dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush); } } void CClockCtrl::GetHandPoints(int nValue, HandType type, CPoint* pPoints) { ASSERT(pPoints); double ratio = 0; switch (type) { case HOUR: { //hour hand goes out to 50% of the radius ratio = 0.5; //Convert the hour angle (0 - 11) to a minute value (0 - 59) //for drawing, then adjust for a gradual transition from hour to hour nValue *= 5; nValue += (m_nMinute / 12); break; } case MINUTE: { //Minute hand goes out to 70% of the radius ratio = 0.7; break; } case SECOND: { //Second hand goes out to 80% of the radius ratio = 0.8; break; } default: { ASSERT(FALSE); break; } } if (type == SECOND) { pPoints[0] = m_MiddlePoint; pPoints[1] = ComputePoint(nValue, ratio); } else { //Compute the face points, First point is the back side, //second point is the right, third point is the top, //and the fourth is left. pPoints[0] = ComputePoint(nValue+30, 0.1); pPoints[1] = ComputePoint(nValue+15, 0.05); pPoints[2] = ComputePoint(nValue, ratio); pPoints[3] = ComputePoint(nValue-15, 0.05); } } void CClockCtrl::OnSize(UINT nType, int cx, int cy) { //Let the parent class do its thing CStatic::OnSize(nType, cx, cy); //Force a recalc of the internal control metrics RecalcLayout(); } void CClockCtrl::RecalcLayout() { //Get the window rect CRect rClient; GetClientRect(&rClient); //Calculate the middle point m_MiddlePoint.x = rClient.Width() / 2; m_MiddlePoint.y = rClient.Height() / 2; //Calculate the radius m_nXRadius = m_MiddlePoint.x; m_nYRadius = m_MiddlePoint.y; //Calculate the width of the marks going around the clock m_nPointWidth = min(m_nXRadius, m_nYRadius) / 20; if (m_nPointWidth < 2) m_nPointWidth = 2; Invalidate(TRUE); } void CClockCtrl::OnTimer(UINT nIDEvent) { //Let the parent class do its thing CStatic::OnTimer(nIDEvent); if (m_nTimerID == nIDEvent) { //Get the local time and force a redraw SYSTEMTIME st; GetLocalTime(&st); SetTime(st.wHour % 12, st.wMinute, st.wSecond); } } void CClockCtrl::SetRealTime(BOOL bRealTime) { m_bEnableRealtime = bRealTime; //Force an explicit refresh of the current state before we go realtime if (m_bEnableRealtime && m_hWnd) { CClientDC dc(this); //Redraw the background CRect rClient; GetClientRect(&rClient); dc.FillSolidRect(rClient, m_ColorBackground); //Redraw the hand DrawHands(dc, m_nHour, m_nMinute, m_nSecond, TRUE); } if (bRealTime) { if (m_nTimerID == 0) { SYSTEMTIME st; GetLocalTime(&st); SetTime(st.wHour % 12, st.wMinute, st.wSecond); m_nTimerID = SetTimer(2, 200, NULL); } } else { if (m_nTimerID) { KillTimer(m_nTimerID); m_nTimerID = 0; } } } BOOL CClockCtrl::GetRealTime() const { return (m_nTimerID != 0); } void CClockCtrl::OnDestroy() { //Turn off timers if we are using them SetRealTime(FALSE); m_bEnableRealtime = TRUE; //Let the parent class do its thing CStatic::OnDestroy(); } void CClockCtrl::SetShowHours(BOOL bShowHours) { if (bShowHours != m_bShowHours) { m_bShowHours = bShowHours; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::SetShowMinutes(BOOL bShowMinutes) { if (bShowMinutes != m_bShowMinutes) { m_bShowMinutes = bShowMinutes; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::SetShowSeconds(BOOL bShowSeconds) { if (bShowSeconds != m_bShowSeconds) { m_bShowSeconds = bShowSeconds; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::SetShowPoints(BOOL bShowPoints) { if (bShowPoints != m_bShowPoints) { m_bShowPoints = bShowPoints; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::SetShowMinorPoints(BOOL bShowMinorPoints) { if (bShowMinorPoints != m_bShowMinorPoints) { m_bShowMinorPoints = bShowMinorPoints; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::SetHourMinutesHandColor(COLORREF color) { if (color != m_ColorHourMinutesHand) { m_ColorHourMinutesHand = color; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::SetBackgroundColor(COLORREF color) { if (color != m_ColorBackground) { m_ColorBackground = color; if (m_hWnd) RedrawWindow(); } } void CClockCtrl::Set3dPoints(BOOL b3dPoints) { if (b3dPoints != m_b3dPoints) { m_b3dPoints = b3dPoints; if (m_hWnd) RedrawWindow(); } } BOOL CClockCtrl::OnEraseBkgnd(CDC* pDC) { CRect rClient; GetClientRect(&rClient); pDC->FillSolidRect(rClient, m_ColorBackground); return TRUE; }